Ext.ux.TreeCombo = Ext.extend(Ext.form.TriggerField, {
	debug : false, // 是否调试
	alignment : "?", // 下拉树布局

	valueField : "id", // 提交值字段,会设置到隐藏域中
	displayField : "text", // 显示字段
	displayDefaultValue : "", // 默认显示值

	hiddenId : null, // 提交隐藏域ID
	hiddenName : null, // 提交隐藏域名称
	hiddenTarget : null, // 提交隐藏域
	hiddenField : null, // 隐藏域
	hiddenDefaultValue : "", // 默认值

	treeWidth : false, // 树的宽度
	checkModel : "multiple", // single:单选,multiple:多选
	cascadeOp : false, // 级联模式, all:上下级联, up:上级联, down:下级联
	postRootNode : false,
	emptyText : "---请选择---",
	initComponent : function() {
		Ext.ux.TreeCombo.superclass.initComponent.call(this);
		this.on('specialkey', function(f, e) {
			if (e.getKey() == e.ENTER) {
				this.onTriggerClick();
			}
		}, this);
	},
	onRender : function(ct, position) {
		Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
		if (this.hiddenName && !this.hiddenTarget) {
			this.hiddenField = this.el.insertSibling({
				tag : 'input',
				type : this.debug ? 'text' : 'hidden',
				name : this.hiddenName,
				id : (this.hiddenId || Ext.id())
			}, 'after', true);
		}
		this.el.on("click", this.onTriggerClick, this);
		if (!this.el.dom.select) {
			this.emptyClass = 'x-form-empty-field-no';
			this.fieldClass = 'x-form-field-no';
			this.wrapFocusClass = 'x-trigger-wrap-focus-no';
			this.focusClass = 'x-form-focus-no';
			if (!this.el.dom.style.cursor) {
				this.el.dom.style.cursor = 'pointer';
			}
			this.el.dom.select = Ext.emptyFn;
		}
	},
	afterRender : function() {
		Ext.ux.TreeCombo.superclass.afterRender.call(this);
	},
	onTriggerClick : function() {
		this.showTree();
	},
	showTree : function() {
		if (!this.tree) {
			if (!this.treeWidth) {
				this.treeWidth = this.el.getWidth();
				this.treeWidth += this.getTriggerWidth();
			}

			if (!this.treeHeight) {
				this.treeHeight = 400;
			}

			if (this.checkModel == 'multiple') {
				this.loader.createNode = K.createInterceptor(this.loader.createNode, function(attr) {
					attr.checked = false;
					return true;
				}, this);
			}

			this.loader.createNode = K.createInterceptor(this.loader.createNode, function(attr) {
				if (this.checkModel == 'multiple') {
					attr.checked = false;
				}
				return true;
			}, this);

			this.tree = new Ext.tree.TreePanel({
				id : this.treeId || "combo-tree-id-" + Ext.id(),
				renderTo : Ext.getBody(),
				loader : this.loader,
				root : this.root,
				rootVisible : (typeof this.rootVisible != 'undefined') ? this.rootVisible : (this.root ? true : false),
				floating : true,
				autoScroll : true,
				width : this.treeWidth,
				height : this.treeHeight,
				checkModel : this.checkModel,
				onlyLeafCheckable : this.onlyLeafCheckable || false,
				listeners : {
					checkchange : this.onCheckchange,
					hide : this.onTreeHide,
					show : this.onTreeShow,
					click : this.onTreeNodeClick,
					// resize : this.onTreeResize,
					scope : this
				}
			});
			this.tree.getRootNode().expand();
			this.echoCheck();
		}
		if (!this.tree.isShow) {
			this.tree.getEl().alignTo(this.wrap, this.alignment);
			this.tree.show();
		}
		return this.tree;
	},
	onTreeResize : function() {
		if (this.tree) {
			this.tree.getEl().alignTo(this.wrap, this.alignment);
		}
	},
	onTreeShow : function() {
		this.tree.isShow = true;
		Ext.getDoc().on('mousewheel', this.collapseIf, this);
		Ext.getDoc().on('mousedown', this.collapseIf, this);
	},
	onTreeHide : function() {
		this.tree.isShow = false;
		Ext.getDoc().un('mousewheel', this.collapseIf, this);
		Ext.getDoc().un('mousedown', this.collapseIf, this);
	},
	onTreeNodeClick : function(node, e) {
		node.getUI().toggleCheck();
		if (this.checkModel == 'single') {
			eXclusiveCheckNode([ this.tree.getRootNode() ], node);
			this.collapse(node);
		}
	},
	onCheckchange : function(node, checked) {
		if (this.checkModel != 'single') {
			switch (this.cascadeOp) {
			case 'all':
				checkedChildrenNodes(node, checked);
			case 'up':
				checkedParentNodes(node, checked);
				break;
			case 'down':
				checkedChildrenNodes(node, checked);
				break;
			}
		} else {
			this.tree.getSelectionModel().select(node);
			eXclusiveCheckNode([ this.tree.getRootNode() ], node);
			this.collapse(node);
		}
	},
	onSelect : function(node) {
		if (this.fireEvent('beforeselect', this, node) !== false) {
			this.setValue(node);
			return this.fireEvent('select', this, node);
		}
		return false;
	},
	collapseIf : function(e) {
		if (!e.within(this.wrap) && !e.within(this.tree.getEl())) {
			this.collapse();
		}
	},
	collapse : function(node) {
		var data = null;
		if (this.checkModel == 'single') {
			data = node;
		} else {
			data = this.tree.getRootNode();
		}
		if (!this.onSelect(data)) {
			return;
		}
		this.tree.hide();
		if (this.resizer) {
			this.resizer.resizeTo(this.treeWidth, this.treeHeight);
		}
		this.assertValue();
	},
	setValue : function(node) {
		if (!node) {
			return;
		}
		if (this.checkModel == 'single') {
			this.value = node[this.displayField] || node.attributes[this.displayField];
			if (this.hiddenField) {
				this.hiddenField.value = node[this.valueField] || node.attributes[this.valueField];
			}
		} else if (this.checkModel == 'multiple') {
			var nodes = getFeatureCheckedNodes(node, this.postRootNode), me = this, values = [], texts = [];
			$.each(nodes, function(i, n) {
				texts.push(n[me.displayField] || n.attributes[me.displayField]);
				values.push(n[me.valueField] || n.attributes[me.valueField]);
			});
			this.value = texts.join(",");
			if (me.hiddenField) {
				me.hiddenField.value = values.join(",");
			}
		}
		this.setRawValue(this.value);
	},
	setRawValue : function(v) {
		if (!this.rendered) {
			return;
		}
		return this.el.dom.value = Ext.isEmpty(v) ? '' : v;
	},
	getRawValue : function() {
		var v = '';
		if (this.rendered) {
			if (this.el.dom.tagName == 'INPUT') {
				v = this.el.getValue();
			} else {
				v = Ext.value(this.value, '');
			}
		}
		return v;
	},
	getValue : function() {
		return this.value;
	},
	initValue : function() {
		if (this.displayDefaultValue) {
			this.value = this.displayDefaultValue;
		} else {
			this.value = this.el.dom.value;
		}
		this.setRawValue(this.value);
		this.originalValue = this.getValue();
		if (this.hiddenField) {
			this.hiddenField.value = this.hiddenDefaultValue || this.hiddenField.value;
		}
	},
	postBlur : function() {
		Ext.ux.TreeCombo.superclass.postBlur.call(this);
		this.assertValue();
	},
	assertValue : function() {
		if (this.el.dom.value == '' || this.el.dom.value == this.emptyText) {
			this.value = '';
		}
		if (!this.value || this.value == '') {
			if (this.hiddenField) {
				this.hiddenField.value = '';
			}
			this.applyEmptyText();
			return false;
		} else {
			this.el.removeClass(this.emptyClass);
		}
		return true;
	},
	destroy : function() {
		Ext.ux.TreeCombo.superclass.destroy.call(this);
		if (this.tree) {
			this.tree.destroy();
		}
	},
	resetCheck : function() {
		checkNode(this.tree.getRootNode(), false);
		eachChildNodes(this.tree.getRootNode(), function(child) {
			checkNode(child, false);
		});
		if (this.hiddenField) {
			this.hiddenField.value = '';
		}
	},
	echoCheck : function() {
		if (this.tree && this.hiddenField) {
			var value = K.trim(this.hiddenField.value);
			if (value.length == 0) {
				return;
			}
			var varr = value.split(","), map = {}, me = this;
			$.each(varr, function(i, v) {
				map[v] = v;
			});
			eachNodes(this.tree.getRootNode(), function(n) {
				// alert(me.tree.getRootNode().childNodes.length)
				// alert(n[me.valueField] ||
				// n.attributes[me.valueField]);
				checkNode(n, map[n[me.valueField] || n.attributes[me.valueField]]);
			});
		}
	}
});

// 级联树
K.Ext.tree.CheckboxTree = Ext.extend(K.Ext.tree.TreePanel, {

	checkRootNode : true, 
	checkModel : "multiple",	//单选或多选
	cascadeOp : "all", 	//级联
	postRootNode : false,

	//初始化
	initComponent : function() {
		if (this.loader) {
			this.loader.createNode = K.createInterceptor(this.loader.createNode, function(attr) {
				if (attr.isRoot) {
					if (this.checkRootNode) {
						attr.checked = attr.checked || false;
					} else {
						delete attr.checked;
					}
				} else {
					attr.checked = attr.checked || false;
				}
				return true;
			}, this);
		}
		K.Ext.tree.CheckboxTree.superclass.initComponent.call(this);
	},
	//监听
	listeners : {
		click : function(node) {
			node.getUI().toggleCheck();
			if (this.checkModel == 'single') {
				eXclusiveCheckNode([ this.getRootNode() ], node);
			}
		},
		checkchange : function(node, checked) {
			if (this.checkModel != 'single') {
				switch (this.cascadeOp) {
				case 'all':
					checkedChildrenNodes(node, checked);
				case 'up':
					checkedParentNodes(node, checked);
					break;
				case 'down':
					checkedChildrenNodes(node, checked);
					break;
				}
			} else {
				this.getSelectionModel().select(node);
				eXclusiveCheckNode([ this.getRootNode() ], node);
			}
		}
	},
	// 清空选中的复选框
	resetCheck : function() {
		checkNode(this.getRootNode(), false);
		eachChildNodes(this.getRootNode(), function(child) {
			checkNode(child, false);
		});
	},
	//设置根节点
	setRootNode : function(node) {
		node.isRoot = true;
		return K.Ext.tree.CheckboxTree.superclass.setRootNode.call(this, node);
	},
	//设置隐藏域
	setValue : function() {
		var nodes = getFeatureCheckedNodes(this.root, this.postRootNode), me = this, values = [], texts = [];
		$.each(nodes, function(i, n) {
			values.push(n[me.valueField] || n.attributes[me.valueField]);
		});
		if (me.hiddenField) {
			me.hiddenField.value = values.join(",");
		}
	},
	// 获取checkboxtree的值
	getValue : function(){
		var nodes = getFeatureCheckedNodes(this.root, true), me = this, values = [], texts = [];
		$.each(nodes, function(i, n) {
			values.push(n[me.valueField] || n.attributes[me.valueField]);
		});
		
		return values.join(",");
	},
	//回显设置
	echoCheck : function(node,echoValue) {
		if (echoValue) {
			var value = K.trim(echoValue);
			if (value.length == 0) {
				return;
			}
			var varr = value.split(","), map = {}, me = this;
			$.each(varr, function(i, v) {
				map[v] = v;
			});
			eachNodes(node, function(n) {
				checkNode(n, map[n[me.valueField] || n.attributes[me.valueField]]);
			});
		}
	}
});

// /////////////////////

// each all node
function eachNodes(root, fn, data) {
	eachChildNodes([ root ], fn, data);
}
// each child
function eachChildNodes(root, fn, data) {
	var childNodes = (root instanceof Array) ? root : root.childNodes;
	if (childNodes) {
		for ( var i = 0; i < childNodes.length; i++) {
			fn(childNodes[i], data);
			eachChildNodes(childNodes[i], fn, data);
		}
	}
}
// down
function checkedChildrenNodes(node, checked) {
	eachChildNodes(node, function(child) {
		checkedChildrenNodes(checkNode(child, checked), checked);
	});
}
// up
function checkedParentNodes(node, checked) {
	if (checked && node.parentNode) {
		checkedParentNodes(checkNode(node.parentNode, checked), checked);
	}
}
// eXclusive
function eXclusiveCheckNode(root, node) {
	eachChildNodes(root, function(child) {
		if (node != child) {
			checkNode(child, false);
		}
	});
}
// check
function checkNode(node, checked) {
	var ui = node.getUI();
	if (ui.checkbox) {
		ui.checkbox.checked = ui.checkbox.defaultChecked = checked;
		node.attributes.checked = checked;
		alert(1);
	}
	return node;
}
function getFeatureCheckedNodes(node, inc) {
	return getCheckedNodes(node, [], inc);
}
// get checked
function getCheckedNodes(node, checkeds, inc) {
	checkeds = checkeds || [];
	inc && node.getUI().isChecked() ? checkeds.push(node) : checkeds;
	return (function _(node, checkeds) {
		if (node.childNodes) {
			for ( var i = 0, child; i < node.childNodes.length; i++) {
				child = node.childNodes[i];
				if (child.getUI().isChecked()) {
					checkeds.push(child);
				}
				_(child, checkeds);
			}
		}
		return checkeds;
	})(node, checkeds);
}
// //////////////////////
